iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 27
0
自我挑戰組

JS 作品實戰應用 - Vue 電商網站系列 第 27

27. Vue 與 API 串接練習

  • 分享至 

  • xImage
  •  

課程練習

此階段是實際串接 API 的差異,串接 API 後的一頁式產品新增、刪除、修改的頁面。
先製作登入頁驗證使用者帳號,再導入產品頁。

登入頁面

// 登入頁面 html
<div id="app">
    <div class="container">
      <form class="form-sognin" @submit.prevent="signin">
        <h1 class="h3  mb-3 font-weight-normal">請先登入</h1>
        <div class="form-group">
          <label for="inputEmail" class="sr-only">Email</label>
          <input type="email" id="inputEmail" 
            v-model="user.email" class="form-control" 
            placeholder="請輸入Email" required
            autofocus>
        </div>
        <div class="form-group">
          <label for="inputPassword" class="sr-only">Email</label>
          <input type="password" id="inputPassword" 
            v-model="user.password" class="form-control" 
            placeholder="請輸入密碼"
            required>
        </div>
        <button class="btn btn-lg btn-primary btn-block" type="submit">
          登入
        </button>
      </form>
    </div>
  </div>
// JS 登入驗證
new Vue({

      //指定
      el: '#app',
      
      //資料
      data: {
        user: {
          email: '',
          password: '',
        },
      },

      //方法
      methods: {
        //登入 , 登入AJAX後 , 把 token(代碼) 和 expired(到期時間) 存到瀏覽器 cookie , 在跳轉頁面
        signin() {
          const api = `https://course-ec-api.hexschool.io/api/auth/login`; //連接登入api
          axios.post(api, this.user).then((response) => {
            const token = response.data.token;  //建立token
            const expired = response.data.expired; //建立expires
            //存到瀏覽器 cookie , 並把 expires 設置有效時間
            document.cookie = `token=${token};expires=${new Date(expired * 1000)};path=/
            `;
            window.location = 'Products.html'; //執行以上程式碼後 , 跳轉到產品頁
            //* 一定要包在裡面 , 放到外面一層會因為非同步原因 , 會先執行跳轉頁面
          }).catch((error) => { //填寫錯誤 , 報出錯誤訊息
            console.log(error);
          });
        },
      },

    })  

產品頁面

// 登入頁面 html
<div id="app" class="container mt-3">
        <div class="text-right mt-4">
            <button class="btn btn-primary" @click="openModal('new')">
                建立新的產品
            </button>
        </div>
        <table class="table mt-4">
            <thead>
                <tr>
                    <th width="15%">分類</th>
                    <th>產品名稱</th>
                    <th>產品圖像</th>
                    <th width="10%">原價</th>
                    <th width="10%">售價</th>
                    <th width="10%">是否啟用</th>
                    <th width="15%">編輯</th>
                </tr>
            </thead>
            <tbody>
                <tr v-for="(item , index) in products" :key="index">
                    <td>{{ item.category }}</td>
                    <td>{{ item.title }}</td>
                    <td><template>
                            <img class="thumb-img" :src="item.imageUrl" alt="">
                        </template></td>
                    <td class="text-right">{{ item.origin_price }}</td>
                    <td class="text-right">{{ item.price }}</td>
                    <td>
                        <span v-if="item.enabled" class="text-success">啟用</span>
                        <span v-else>未啟用</span>
                    </td>
                    <td>
                        <div class="btn-group">
                            <button class="btn btn-outline-primary btn-sm mr-2"
                                @click="openModal('edit' , item)" 
                                :disabled="loadingBtn === item.id">
                                <span class="spinner-border spinner-border-sm" 
                                role="status" aria-hidden="true" 
                                v-if="loadingBtn === item.id"></span>
                                編輯</button>
                            <button class="btn btn-outline-danger btn-sm"
                                @click="openModal('delete' , item)">刪除</button>
                        </div>
                    </td>
                </tr>
            </tbody>
        </table>
        <!--分頁-->
        <pagination :pages="pagination" @update="getProducts"></pagination>


        <!-- productModal -->
        <div id="productModal" class="modal fade" tabindex="-1" role="dialog" 
        aria-labelledby="exampleModalLabel"
            aria-hidden="true">
            <modal :api="api" :temp-product="tempProduct" @updata="getProducts"></modal>
        </div>
        <!--productModal END -->

        <div id="delProductModal" class="modal fade" tabindex="-1" role="dialog" 
        aria-labelledby="exampleModalLabel"
            aria-hidden="true">
            <div class="modal-dialog" role="document">
                <div class="modal-content border-0">
                    <div class="modal-header bg-danger text-white">
                        <h5 id="exampleModalLabel" class="modal-title">
                            <span>刪除產品</span>
                        </h5>
                        <!-- 關閉按鈕-->
                        <button type="button" class="close" data-dismiss="modal" 
                        aria-label="Close">
                            <span aria-hidden="true">&times;</span>
                        </button>
                    </div>
                    <!--modal-header END -->

                    <div class="modal-body">
                        是否刪除 <strong class="text-danger">{{ tempProduct.title }}</strong> 
                    商品(刪除後將無法恢復)。
                    </div>
                    <!--modal-bady END -->

                    <div class="modal-footer">
                        <button class="btn btn-outline-secondary" type="button" 
                        data-dismiss="modal">取消</button>
                        <button class="btn btn-danger" type="button" @click="delProduct">
                        確認刪除</button>
                    </div>
                    <!--modal-footer END -->

                </div>
            </div>
        </div>
        <!--delProductModal END -->

    </div>
// 產品頁JS
new Vue({

    //指定    
    el: '#app',

    //資料
    data: {
        products: [],
        pagination: {},
        tempProduct: {
            imageUrl: []
        },
        api: {
            uuid: '',
            path: ''
        },
        token: '',
        isNew: '',
        loadingBtn: '',
    },


    //創建
    created() {
        //取得存在 cookie 中的 token
        this.token = document.cookie.replace(/(?:(?:^|.*;\s*)token\s*\=\s*([^;]*).*$)|^.*$/, "$1");
        //預設帶入 token
        axios.defaults.headers.common.Authorization = `Bearer ${this.token}`;
        this.getProducts();
    },

    //方法
    methods: {
        //開啟視窗
        openModal(isNew, item) {
            switch (isNew) {
                //新增
                case 'new':
                    this.tempProduct = { imageUrl: [] };
                    $('#productModal').modal('show');
                    break;
                //編輯
                case 'edit':
                    //讀取效果
                    this.loadingBtn = item.id;
                    //取得遠端單筆資料
                    const url = `${this.api.path}${this.api.uuid}/admin/ec/product/${item.id}`;
                    //取得遠端資料
                    axios.get(url).then((res) => {
                        this.tempProduct = res.data.data;
                        $('#productModal').modal('show');
                        this.loadingBtn = '';
                    }); 
                    break;
                //刪除
                case 'delete':
                    this.tempProduct = Object.assign({}, item);
                    $('#delProductModal').modal('show');
                    break;
                default:
                    break;
            }
        },

        //刪除資料
        delProduct() {
            if (this.tempProduct.id) {
                const id = this.tempProduct.id;
                this.products.forEach((item, i) => {
                    if (item.id === id) {
                        this.products.splice(i, 1);
                        this.tempProduct = {};
                    }
                });
            }
            $('#delProductModal').modal('hide');
        },

        //取得資料
        getProducts(num = 1) {
            //取得遠端後台管理API
            const url = `${this.api.path}${this.api.uuid}/admin/ec/products?page=${num}`;
            //取得遠端資料
            axios.get(url).then((res) => {
                this.products = res.data.data;
                this.pagination = res.data.meta.pagination;

                if (this.tempProduct.id) {
                    this.tempProduct = {
                        imageUrl: [],
                    };  
                    $('#productModal').modal('hide');                  
                };

            });
        },
    },
});

上一篇
26. 產品管理頁面
下一篇
28. 表單驗證
系列文
JS 作品實戰應用 - Vue 電商網站30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言